/**
 * 
 */
package org.statewalker.core;

import java.util.HashMap;
import java.util.Map;

import org.statewalker.fsm.providers.CompositeFsmTransitionsRegistry;
import org.statewalker.fsm.providers.FsmTransitionsRegistry;

/**
 * @author kotelnikov
 */
public class ProcessDescriptor {

    protected IStateFactory fDefaultFactory = AsyncState.FACTORY;

    protected Map<String, IStateFactory> fFactories = new HashMap<String, IStateFactory>();

    private Map<String, String> fProcessorKeyMap = new HashMap<String, String>();

    protected CompositeFsmTransitionsRegistry fRegistry = new CompositeFsmTransitionsRegistry();

    public ProcessDescriptor() {
    }

    public FsmTransitionsRegistry addNewRegistry() {
        FsmTransitionsRegistry registry = new FsmTransitionsRegistry();
        fRegistry.addRegistry(registry);
        return registry;
    }

    public IStateFactory getDefaultFactory() {
        return fDefaultFactory;
    }

    public synchronized String getProcessorKey(String stateKey) {
        return fProcessorKeyMap.get(stateKey);
    }

    public CompositeFsmTransitionsRegistry getRegistry() {
        return fRegistry;
    }

    public Process newProcess(
        String processKey,
        IProcessContext context,
        IStateExecutor executor,
        ILock lock,
        int mask) {
        return new Process(this, executor, context, lock, processKey, mask);
    }

    protected IState newState(
        Process process,
        IEvent event,
        final String stateKey) {
        IStateFactory factory = fFactories.get(stateKey);
        if (factory == null) {
            factory = fDefaultFactory;
        }
        IState result = factory.newState(stateKey);
        if (result != null) {
            result.setKey(stateKey);
            IProcessContext context = process.getContext();
            result.setContext(context);
            IState parent = process.getCurrent();
            result.setParent(parent);
        }
        return result;
    }

    public synchronized void removeProcessorKey(String stateKey) {
        setProcessorKey(stateKey, null);
    }

    public void removeRegistry(FsmTransitionsRegistry registry) {
        fRegistry.removeRegistry(registry);
    }

    public synchronized void removeStateFactory(
        String key,
        IStateFactory factory) {
        Map<String, IStateFactory> factories = new HashMap<String, IStateFactory>(
            fFactories);
        IStateFactory n = factories.remove(key);
        if (n == factory) {
            fFactories = factories;
        }
    }

    public void setDefaultFactory(IStateFactory defaultFactory) {
        fDefaultFactory = defaultFactory;
    }

    public synchronized void setProcessorKey(
        String stateKey,
        String processorKey) {
        if (processorKey == null) {
            fProcessorKeyMap.remove(stateKey);
        }
        fProcessorKeyMap.put(stateKey, processorKey);
    }

    public synchronized void setStateFactory(String key, IStateFactory factory) {
        Map<String, IStateFactory> factories = new HashMap<String, IStateFactory>(
            fFactories);
        factories.put(key, factory);
        fFactories = factories;
    }

}
